#region Using directives

using System;
using System.Collections.Generic;
using System.Text;

using Weazel.Math;

#endregion

namespace Weazel.Gezel.Simulator.Reference
{
    /// <summary>
    /// HACK, which allows us to distinguish between
    /// signals and registers when printing profiling information.
    /// </summary>
    class RegisterInternalSignal : Signal
    {
        public RegisterInternalSignal(Simulation sim, DatapathContext datapathContext, Symid id, int width, int sign, string name, bool isUserDefined)
            :
            base(sim, datapathContext, id, width, sign, name, isUserDefined) { }
    }

    class RegisterSignal : AbstractSignal
    {
        /// <summary>
        /// Register input
        /// </summary>
        private RegisterInternalSignal registerInput;

        /// <summary>
        /// Register output
        /// </summary>
        private readonly Integer registerOutput;

        public RegisterSignal(Simulation sim, DatapathContext context, Symid id, int wordlength, int sign, string name)
            : base(id, name)
        {
            registerInput = new RegisterInternalSignal(sim, context, id, wordlength, sign, null, false);
            registerOutput = new Integer(wordlength, sign == 1);
        }

        public void UpdateIn(long g)
        {
            if (registerInput.HasDefiner())
                registerInput.Evaluate(null, g);

            // because register can be left undefined in a particular 
            // clock always advance to current generation
            generation = g;
        }

        internal override void Assign(Integer nv)
        {
            registerInput.Assign(nv);
        }


        public void Tick()
        {
            //      // for global sleep
            //      if (ri.peekval() != *ro) {
            //        glbRTSleep.cannotSleep();
            //        //    cerr << "Reg ticks\n";
            //
            //        if (glbRTDebug) {
            //          cout << setw(20) << peekval();
            //          cout << setw(20) << ri.peekval() << " ";
            //          glbSymboltable.showlex(cout, id);
            //          cout << "\n";
            //        }
            //
            //      } 
            //
            //      #ifdef RTACTIVITY
            //        if (*ro != ri.peekval()) 
            //          glbRTActivityEffUpdate++;
            //        glbRTActivityUpdate++;
            //      #endif

            registerOutput.ValueCopy(registerInput.PeekValue());

            if ((int)registerInput.PeekValue().content[0] == -4)
            {
            }

        }

        internal override uint Width()
        {
            return registerInput.Width();
        }


        internal override uint Signed()
        {
            return registerInput.Signed();
        }


        internal override Integer Evaluate(AbstractIpBlock ip, long target_generation)
        {
            generation = target_generation;
            return registerOutput;
        }

        internal override void newDefiner(Symid sfg, AbstractSignal definer)
        {
            registerInput.newDefiner(sfg, definer);
        }

        internal override void defineDriver(AbstractSignal artsignal)
        {
            registerInput.defineDriver(artsignal);
        }

        public override bool IsGeneration(long g)
        {
            return generation == g;
        }

        public override void Show(StringBuilder buffer)
        {
            buffer.Append(registerOutput.ToString(this.@base));
            buffer.Append('/');
            buffer.Append(registerInput.PeekValue().ToString(this.@base));
        }

        public override bool TraceToSignal(Symid toSignalId, List<AbstractSignal> signals)
        {
            return false;
        }
    }
}